#pragma once    //   U҉U҉U	 for unicoude save
#include "wOHandle.hpp"
#include "ProObjects.h"
#include <memory>
#include "wCollection.hpp"
#include "ProElement.h"
#include "wProException.hpp"



namespace witotk{

	class wProElement:public wOHandle<ProElement>
	{
	public:
		wProElement()
		{

		}
		wProElement(ProElement suf):wOHandle<ProElement>(suf)
		{
		}

		ProValueDataType GetValuetype()
		{
			ProValueDataType type; 
			ProError error = ProElementValuetypeGet(m_data,&type);
			PROE_THROW(error,"GetValuetype");
			return type;
		}

		ProReference GetReference()
		{
			ProReference ref; 
			ProError error = ProElementReferenceGet(m_data,NULL,&ref);
			PROE_THROW(error,"GetReference");
			return ref;
		}

		ProAppData GetSpecialvalue()
		{
			ProAppData ref; 
			ProError error = ProElementSpecialvalueGet(m_data,NULL,&ref);
			PROE_THROW(error,"GetSpecialvalue");
			return ref;
		}
		void SetSpecialvalue(ProAppData ref)
		{
			ProError error = ProElementSpecialvalueSet(m_data,ref);
			PROE_THROW(error,"SetSpecialvalue");
		}

	};

	typedef	std::tr1::shared_ptr<wProElement> wProElement_ptr;

	typedef	wCollectionshared_ptr<wCollection<wProElement>> wProElementCollection_ptr;

	typedef	wCollection<wProElement> wProElementCollection;

//element tree build
	struct ElementValue_no_tag{};
	struct ElementValue_noArg_tag{};

	struct ElementValue_Array_tag{};
	typedef ElementValue_Array_tag Array;

	struct ElementValue_Compound_tag{};
	typedef ElementValue_Compound_tag Compound;

	struct ElementValue_SELECTION_tag{};
	typedef ElementValue_SELECTION_tag SELECTION;
	

	template<int EleId>
	class wProElementBase_T:public wProElement
	{
	public:
		wProElementBase_T()
		{
			ProElementAlloc ( EleId, &m_data );
		}
	};

	template<int EleId
		,class ValType = ElementValue_no_tag
		,class ArgItem = ElementValue_noArg_tag
		>
	class wProElement_T:public wProElementBase_T<EleId>
	{
	public:
	};

	template<int EleId>
	class wProElement_T<EleId,int>:public wProElementBase_T<EleId>
	{
	public:
		wProElement_T(int feat_type_id)
		{
			ProElementIntegerSet(m_data,feat_type_id);
		}
	};
	template<int EleId>
	class wProElement_T<EleId,double>:public wProElementBase_T<EleId>
	{
	public:
		wProElement_T(double val)
		{
			ProElementDecimalsSet(m_data,6);
			ProElementDoubleSet(m_data,val);
		}
	};


	template<int EleId >
	class wProElement_T<EleId,wchar_t*>:public wProElementBase_T<EleId>
	{
	public:
		wProElement_T(wchar_t* value)
		{
			ProElementWstringSet(m_data,value);
		}
		wProElement_T(char* value)
		{
			ProElementStringSet(m_data,value);
		}
	};

	template<int EleId >
	class wProElement_T<EleId,char*>:public wProElementBase_T<EleId>
	{
	public:
		wProElement_T(wchar_t* value)
		{
			ProElementWstringSet(m_data,value);
		}
		wProElement_T(char* value)
		{
			ProElementStringSet(m_data,value);
		}
	};



	template<int EleId>
	class wProElement_T<EleId,Compound>:public wProElementBase_T<EleId>
	{
	public:
		wProElement_T()
		{
		}
		wProElement_T& operator[](const wProElement& elem)
		{
			ProError error = ProElemtreeElementAdd(m_data,NULL,elem.data()); 
			PROE_THROW(error,"wProElement_T<EleId,Compound>::[]");
			return *this;
		}
	};

	template<int EleId,class ArgItem>
	class wProElement_T<EleId,Array,ArgItem>:public wProElementBase_T<EleId>
	{
	public:
		wProElement_T(){	 }
		wProElement_T& operator[](const ArgItem& elem)
		{
			ProError error = ProElemtreeElementAdd(m_data,NULL,elem.data()); 
			PROE_THROW(error,"wProElement_T<EleId,Array>::[]");
			return *this;
		}
	};

	template<int EleId>
	class wProElement_T<EleId,SELECTION>:public wProElementBase_T<EleId>
	{
	public:
		wProElement_T(ProSelection selection)
		{
			ProReference ref;
			ProError error = ProSelectionToReference(selection,&ref);
			error = ProElementReferenceSet(m_data,ref);
		}
	};

	typedef wProElement_T<PRO_E_FEATURE_TYPE,int> FEATURE_TYPE;
	typedef wProElement_T<PRO_E_STD_FEATURE_NAME,wchar_t*> FEATURE_NAME;

	typedef wProElement_T<PRO_E_CSYS_ORIGIN_CONSTR,Compound> CSYS_ORIGIN_CONSTR;
	typedef wProElement_T<PRO_E_CSYS_ORIGIN_CONSTRS,Array,CSYS_ORIGIN_CONSTR> CSYS_ORIGIN_CONSTRS;
	
	typedef wProElement_T<PRO_E_CSYS_ORIGIN_CONSTR_REF,SELECTION> CSYS_ORIGIN_CONSTR_REF;
	typedef wProElement_T<PRO_E_CSYS_OFFSET_TYPE,int> CSYS_OFFSET_TYPE;

	typedef wProElement_T<PRO_E_CSYS_ORIENTMOVE,Compound> CSYS_ORIENTMOVE;
	typedef wProElement_T<PRO_E_CSYS_ORIENTMOVES,Array,CSYS_ORIENTMOVE> CSYS_ORIENTMOVES;

	typedef wProElement_T<PRO_E_CSYS_ORIENTMOVE_MOVE_TYPE,int> CSYS_ORIENTMOVE_MOVE_TYPE;
	typedef wProElement_T<PRO_E_CSYS_ORIENTMOVE_MOVE_VAL,double> CSYS_ORIENTMOVE_MOVE_VAL;
	typedef wProElement_T<PRO_E_CSYS_ORIENT_BY_METHOD,int> CSYS_ORIENT_BY_METHOD;

	

//element tree build end



	class wProElemtree:public wProElement
	{
	public:
		wProElemtree()
		{
			ProElementAlloc ( PRO_E_FEATURE_TREE, &m_data );
		}
		wProElemtree(ProElement suf):wProElement(suf)
		{
		}
		~wProElemtree()
		{
			ProElementFree(&m_data);
		}

		wProElement_ptr GetElement( ProElempath elempath )
		{
			ProElement elem  ;
			ProError error = ProElemtreeElementGet (m_data,elempath,&elem);
			PROE_THROW(error,"GetElement");
			wProElement_ptr pe(new wProElement(elem));
			return pe;
		}
		

		void AddElement(ProElempath   elempath,ProElement    elem)
		{
			 ProError error = ProElemtreeElementAdd(m_data,elempath,elem)  ;
			 PROE_THROW(error,"AddElement");
		}

		wProElemtree& operator[](const wProElement& ele)
		{
			AddElement(NULL,ele.data()); 
			return *this;
		}
	};

	typedef	std::tr1::shared_ptr<wProElemtree> wProElemtree_ptr;

	typedef	wCollectionshared_ptr<wCollection<wProElemtree>> wProElemtreeCollection_ptr;

	typedef	wCollection<wProElemtree> wProElemtreeCollection;

	class wProElemtreeCopy:public wProElemtree
	{
	public:
		wProElemtreeCopy(ProElement suf):wProElemtree(suf)
		{
			 m_owner.id = 0;
			 m_owner.owner = NULL;
			 m_owner.type = PRO_TYPE_UNUSED;
		}
		~wProElemtreeCopy()
		{
			ProFeatureElemtreeFree(&m_owner,m_data);
		}
		ProFeature m_owner;
	};

	typedef	std::tr1::shared_ptr<wProElemtreeCopy> wProElemtreeCopy_ptr;

}